import React, { useEffect, useState, useRef } from 'react'
import localforage from 'localforage'
import PubSub from 'pubsub-js'
import { nanoid } from 'nanoid'
import styles from './index.module.less'
import DialogList from './DialogList'
import ChattingBox from './ChattingBox'
import { getGlobalState } from '@/utils/qiankunActions'
import {
  sseConnectChattingApi,
  getNotReadMessageCountApi,
  sseSendChattingMessageApi,
  sseCheckChattingNotReceiveMessageApi,
} from '@/request/api/chatHistory'
import { getFriendInfoApi } from '@/request/api/friend'
import MessageQueueClass from '@/utils/utilsClass/MessageQueue'

//
//
export default function Chatting() {
  // 消息队列实例
  const MessageQueue = new MessageQueueClass()

  // SSE 相关
  // sse 聊天实例
  const eventSource = useRef<EventSource>(null)

  useEffect(() => {
    sseConnectChatting()
    // 设置消息处理回调函数
    MessageQueue.setHandlerFn(setUserChatRecord)

    return () => {
      eventSource.current.close()
      console.log('\x1b[1m\x1b[31m%s\x1b[0m', 'chatting SSE 已关闭')
    }
  }, [])

  // 连接聊天 SSE
  const sseConnectChatting = () => {
    eventSource.current = sseConnectChattingApi()

    eventSource.current.onopen = function (event) {
      console.log('\x1b[1m\x1b[34m%s\x1b[0m', 'chatting SSE 连接成功')
    }

    eventSource.current.onmessage = function (event) {
      console.log(
        '\x1b[1m\x1b[32m%s\x1b[0m',
        'chatting SSE 收到消息',
        event.data
      )
      const record: chatRecordItf = JSON.parse(event.data)
      const { message, masterId, receiverId, type, createTime } = record

      // 判断发送过来的消息是否为聊天对话消息
      if (message && masterId && receiverId && type && createTime) {
        record.id = nanoid() // 消息发送过来时，数据还没有写入到数据库，没有id
        // setUserChatRecord(record)
        MessageQueue.receiveMessage(record) // 将传递过来的消息推进消息队列
      }
    }

    eventSource.current.onerror = function (event) {
      console.log('chatting SSE 连接失败', event)
    }

    // 监听未读消息，处理传递过来的批量消息记录
    eventSource.current.addEventListener('notReadRecordList', function (e) {
      const data = JSON.parse(e.data)
      console.log('chatting SSE 监听 notReadRecordList 事件成功 ', data)

      data.reduce((accumulator: number, item: chatRecordItf) => {
        MessageQueue.receiveMessage(item) // 将传递过来的消息推进消息队列
        // setTimeout(() => setUserChatRecord(item), accumulator)
        // return accumulator + 200
      }, 0)
    })
  }

  //
  //
  // 聊天相关

  // 聊天用户列表
  const [userChatList, setUserChatList] = useState<localChatUsersItf[]>([])
  // 当前聊天对话框 目标id
  const [currentChatTargetId, setCurrentChatTargetId] = useState<string>('')
  // 当前聊天对话框用户id ref，脱离生命周期
  const currentChatUserIdRef = useRef<string>(currentChatTargetId)
  // 当前用户聊天窗口最新消息
  const [lastestRecord, setLastestRecord] = useState<chatRecordItf[]>([])

  useEffect(() => {
    // 进入页面时获取未读消息
    sseCheckChattingNotReceiveMessageApi()
    // 获取浏览器本地聊天用户列表
    getLocalChatUsers()

    // 通过监听获取用户的本地聊天记录，并进行处理
    ;(window as any)?.localFile.sendUserChatting((record: chatRecordItf[]) =>
      setLastestRecord([...record])
    )

    // 当最新消息已经写入到本地和渲染到对话框中时，清除最新消息
    const unsubscribeOne = PubSub.subscribe('addRecordFinishHandler', () => {
      setLastestRecord([])
    })
    // 监听消息对话框传递过来的刷新事件
    const unsubscribeTwo = PubSub.subscribe('refreshChatUserList', () => {
      getLocalChatUsers()
    })

    return () => {
      PubSub.unsubscribe(unsubscribeOne)
      PubSub.unsubscribe(unsubscribeTwo)
    }
  }, [])

  //
  // 监听当前聊天用户id的变化情况
  // 通过选择聊天列表和下拉框用户来选择聊天用户
  useEffect(() => {
    currentChatUserIdRef.current = currentChatTargetId
    if (!currentChatTargetId) return
    initUserLocalChat(currentChatTargetId) // 判断初始化一下第一次聊天的用户
    getUserChatRecord(currentChatTargetId) // 获取用户本地聊天记录
  }, [currentChatTargetId])

  // 初始化本地聊天用户，将第一次聊天的用户缓存到浏览器（第一次主动与对方交流）
  const initUserLocalChat = async (chatUserId: string) => {
    const { account } = getGlobalState().userInfo
    const data: { [key: string]: localChatUsersItf } =
      (await localforage.getItem(`${account}-chatList`)) || {}

    // 不是第一次聊天，则无需初始化
    if (data[chatUserId]) return

    let avatar: string = ''
    let nickname: string = ''
    const res = await getFriendInfoApi(chatUserId)
    if (res.code === 200) {
      avatar = res.data.avatar
      nickname = res.data.nickname
    }
    data[chatUserId] = {
      record: null,
      notCount: 0,
      chatUserId: chatUserId,
      createTime: new Date().getTime().toString(),
      nickname: nickname,
      avatar: avatar,
    }

    await localforage.setItem(`${account}-chatList`, data)
    getLocalChatUsers()
  }

  // 获取与当前用户的本地聊天记录
  const getUserChatRecord = (chatUserId: string) => {
    const { account } = getGlobalState().userInfo
    ;(window as any).localFile.getUserChatting(account, chatUserId)
    // 获取用户本地聊天记录,主应用会接收到本地聊天记录,
  }

  //
  // 当 SSE 连接发送聊天消息过来时
  // 设置用户聊天记录到本地
  const setUserChatRecord = (chatRecord: chatRecordItf) => {
    const { id } = getGlobalState().userInfo
    const { masterId, receiverId } = chatRecord

    // 判断消息是对方发给自己的还是自己发给对方的,提取出聊天对象用户id
    const chatUserId = masterId !== id ? masterId : receiverId
    setRecordHandler(chatUserId, chatRecord)
    return

    //
    // 设置消息
    function setRecordHandler(chatUserId: string, record: chatRecordItf) {
      const { account } = getGlobalState().userInfo
      // 设置消息记录到本地
      ;(window as any).localFile.setUserChatting(account, chatUserId, record)

      // 设置最新记录到浏览器缓存
      setLatestChatRecord(chatUserId, record)

      // 如果该消息是当前聊天框用户发来的，则设置最新消息
      if (chatUserId === currentChatUserIdRef.current)
        setLastestRecord([record])
    }

    //
    // 根据聊天用户id设置最新消息记录到浏览器缓存
    async function setLatestChatRecord(
      chatUserId: string,
      chatRecord: chatRecordItf
    ) {
      const { account, id } = getGlobalState().userInfo
      let data: { [key: string]: localChatUsersItf } =
        (await localforage.getItem(`${account}-chatList`)) || {}

      // 本地浏览器有该用户缓存处理操作
      if (data[chatUserId]) {
        data[chatUserId].record = chatRecord
        data[chatUserId].chatUserId = chatUserId
        data[chatUserId].createTime = new Date().getTime().toString()
        if (chatRecord.masterId === id) data[chatUserId].notCount = 0
        else {
          if (!data[chatUserId].notCount) data[chatUserId].notCount = 1
          else data[chatUserId].notCount = data[chatUserId].notCount + 1
        }
      }

      // 本地浏览器没有缓存处理操作 （对方主动第一次与你交流，进行初始化）
      if (!data[chatUserId]) {
        let avatar: string = ''
        let nickname: string = ''
        const res = await getFriendInfoApi(chatUserId)
        if (res.code === 200) {
          avatar = res.data.avatar
          nickname = res.data.nickname
        }
        data[chatUserId] = {
          record: chatRecord,
          notCount: chatRecord.masterId === id ? 0 : 1,
          chatUserId: chatUserId,
          createTime: new Date().getTime().toString(),
          avatar: avatar,
          nickname: nickname,
        }
      }

      await localforage.setItem(`${account}-chatList`, data)
      getLocalChatUsers()
    }
  }

  //
  // 获取本地浏览器聊天用户列表,及其最新的一条消息记录
  const getLocalChatUsers = async () => {
    const { account } = getGlobalState().userInfo
    const data: { [key: string]: localChatUsersItf } =
      (await localforage.getItem(`${account}-chatList`)) || {}

    let arr = Object.values(data)
    arr.sort((a, b) => Number(b.createTime) - Number(a.createTime))
    setUserChatList([...arr])
  }

  return (
    <div className={styles.ChattingContainer}>
      {/* 对话列表 */}
      <DialogList
        chatUsersList={userChatList}
        setCurrentChatUserId={setCurrentChatTargetId}
        currentChatUsertId={currentChatTargetId}
      />

      {/* 聊天框 */}
      {currentChatTargetId ? (
        <ChattingBox
          chatRecordList={lastestRecord}
          chatUserId={currentChatTargetId}
        />
      ) : null}
    </div>
  )
}
